#include "concurrent_combination_solver.h"
#include <QEventLoop>
#include <QTimer>
#include <QPointer>
#include <QUuid>
#include <QHash>
#include <chrono>
#include <algorithm>

#include <utility>

#include "infrastructure/tasking/task_manager.h"
#include "infrastructure/tasking/task_command.h"

namespace tasking = base::tasking;
namespace application {
namespace dispatcher {

namespace {
constexpr double kDefaultSuboptimality = 1.5;
}

ConcurrentCombinationSolver::ConcurrentCombinationSolver(QObject* parent)
    : QObject(parent)
{
}

ConcurrentCombinationSolver::~ConcurrentCombinationSolver() = default;

ConcurrentCombinationSolver::SolveResult
ConcurrentCombinationSolver::solveWithFallback(
    const std::vector<SolveCandidate>& candidates,
    PathfindingGraphPtr graph,
    std::shared_ptr<kernel::ILogger> logger,
    double timeout)
{
    if (candidates.empty()) {
        SolveResult result;
        result.success = false;
        result.errorMessage = "没有候选组合";
        return result;
    }

    if (!graph || graph->isEmpty()) {
        SolveResult result;
        result.success = false;
        result.errorMessage = "路径图为空";
        return result;
    }

    // ========== 第1步：初始化并发求解环境 ==========

    // 重置求解状态
    m_solutionFound = false;
    m_bestResult = std::nullopt;

    // 创建共享的取消标志（用于工作函数内部快速检查）
    // 当首个任务成功时，设置此标志通知其他正在执行的任务提前退出
    auto cancelFlag = std::make_shared<std::atomic<bool>>(false);

    // 生成批次ID（用于 TaskManager 批量取消队列中未执行的任务）
    const QString batchId = QUuid::createUuid().toString(QUuid::WithoutBraces);

    // 创建 TaskManager 线程池
    // workerCount: 动态计算工作线程数，最多4个，不超过候选数量（避免创建过多空闲线程）
    const int workerCount = std::max(1, std::min<int>(static_cast<int>(candidates.size()), 4));
    tasking::TaskManager manager(workerCount, logger);

    // ========== 第2步：准备同步等待机制 ==========

    // 预分配结果数组（每个索引只被一个线程写入，无需加锁）
    std::vector<SolveResult> results(candidates.size());

    // QEventLoop: 用于阻塞主线程，等待异步任务完成
    QEventLoop loop;
    // QPointer: 防止 loop 被销毁后访问（lambda 捕获安全）
    QPointer<QEventLoop> loopGuard(&loop);

    // 任务完成计数器
    int completedCount = 0;
    const int totalCount = static_cast<int>(candidates.size());
    bool deadlineReached = false;

    // ========== 第3步：设置全局超时保护 ==========

    // 全局超时定时器（所有候选方案的总时间限制）
    QTimer deadlineTimer;
    deadlineTimer.setSingleShot(true);
    if (timeout > 0.0) {
        deadlineTimer.start(static_cast<int>(timeout * 1000));
        connect(&deadlineTimer, &QTimer::timeout, &loop, [&, loopGuard]() {
            deadlineReached = true;
            if (loopGuard) {
                loopGuard->quit();  // 超时后退出事件循环
            }
        });
    }

    // ========== 第4步：创建并提交所有任务 ==========

    // 保存所有任务句柄（用于监听完成信号）
    std::vector<tasking::TaskHandle::Ptr> handles;
    handles.reserve(candidates.size());

    for (size_t i = 0; i < candidates.size(); ++i) {
        const auto& candidate = candidates[i];

        // 准备任务数据（将在工作线程中执行）
        SolveTask solveTask;
        solveTask.candidate = candidate;
        solveTask.graph = graph;
        solveTask.logger = logger;
        solveTask.timeout = timeout;
        solveTask.suboptimality = kDefaultSuboptimality;  // keep solver heuristic separate from timeout
        solveTask.candidateIndex = static_cast<int>(i);
        solveTask.cancelFlag = cancelFlag;  // 共享取消标志

        // 创建 TaskCommand（任务命令）
        auto command = std::make_shared<tasking::TaskCommand>();
        command->batchId = batchId;                      // 批次ID，用于批量取消
        command->priority = tasking::TaskPriority::High; // 高优先级（路径规划是关键任务）
        command->retryPolicy.maxRetries = 0;             // 不重试（求解失败直接放弃该候选）

        // 定义工作函数（在 DbWorkerThread 中执行）
        command->work = [this, solveTask, &results, i](const tasking::TaskHandle::Ptr& handle) -> tasking::TaskResult {
            // 设置单任务超时（TaskHandle 内部的超时保护）
            if (handle && solveTask.timeout > 0.0) {
                handle->setTimeout(static_cast<int>(solveTask.timeout * 1000));
            }

            // 复制任务数据，避免 lambda 捕获引用导致的生命周期问题
            SolveTask taskCopy = solveTask;
            if (handle) {
                // 传递 CancellationToken，让工作函数能检查取消状态
                taskCopy.cancellationToken = handle->cancellationToken();
            }

            // 执行实际求解（调用 executeSolveTask）
            auto res = executeSolveTask(taskCopy);

            // 存储结果到共享数组（线程安全：每个索引只被一个线程写入）
            results[i] = res;

            // 返回 TaskResult（通知 TaskManager 任务完成状态）
            if (res.success) {
                return tasking::TaskResult::successResult();
            }
            return tasking::TaskResult::failureResult(kernel::ErrorCode::InvalidOperation, res.errorMessage);
        };

        // 提交任务到 TaskManager，获取任务句柄
        auto handle = manager.enqueue(command);
        handles.push_back(handle);

        // ========== 第5步：监听任务完成信号（竞速逻辑） ==========

        // 连接 TaskHandle 的 taskFinished 信号（在主线程执行）
        connect(handle.get(), &tasking::TaskHandle::taskFinished, this,
                [&, idx = static_cast<int>(i), loopGuard](const tasking::TaskResult& taskResult) {
                    completedCount++;

                    // 【竞速模式】首个成功的任务
                    if (taskResult.success && !m_solutionFound.load()) {
                        QMutexLocker locker(&m_resultMutex);
                        // 双重检查锁（防止多个线程同时进入）
                        if (!m_solutionFound.load()) {
                            // 保存最佳结果
                            if (idx < static_cast<int>(results.size())) {
                                m_bestResult = results[idx];
                            }
                            m_solutionFound = true;

                            // 双重取消机制：
                            // 1. 设置自定义取消标志（通知正在执行的任务提前退出）
                            *cancelFlag = true;
                            // 2. 取消队列中未执行的任务（通过 batchId）
                            manager.cancelBatch(batchId);

                            // 记录成功日志
                            if (m_bestResult && logger) {
                                logger->info(QString("并发求解成功：候选#%1（包含%2个AGV，排除%3个AGV，耗时%4s）")
                                                 .arg(m_bestResult->candidateIndex)
                                                 .arg(m_bestResult->solvedAgvs.size())
                                                 .arg(m_bestResult->failedAgvs.size())
                                                 .arg(m_bestResult->solveTime, 0, 'f', 3));
                            }

                            // 退出事件循环（结束等待）
                            if (loopGuard) {
                                loopGuard->quit();
                            }
                            return;
                        }
                    }

                    // 所有任务完成（无成功）
                    if (completedCount >= totalCount && loopGuard) {
                        loopGuard->quit();
                    }
                });
    }

    // ========== 第6步：阻塞等待所有任务完成 ==========

    // 阻塞当前线程，等待事件循环退出（三种退出条件）：
    // 1. 首个任务成功 → loopGuard->quit()
    // 2. 全局超时 → deadlineTimer 触发 quit()
    // 3. 所有任务完成 → completedCount >= totalCount 触发 quit()
    loop.exec();

    // 停止 TaskManager，等待所有工作线程结束
    manager.stop();

    // ========== 第7步：返回求解结果 ==========

    if (m_bestResult.has_value()) {
        // 成功：返回首个成功的候选方案
        return m_bestResult.value();
    } else if (deadlineReached) {
        // 全局超时：所有候选方案均未在时限内完成
        SolveResult result;
        result.success = false;
        result.errorMessage = QString("并发求解全局超时 (%1s)").arg(timeout, 0, 'f', 3);
        if (logger) {
            logger->warning(result.errorMessage);
        }
        return result;
    } else {
        // 全部失败：所有候选方案均求解失败
        SolveResult result;
        result.success = false;
        result.errorMessage = "所有候选组合均求解失败";

        if (logger) {
            logger->warning(QString("并发求解失败：尝试了%1个组合，均未成功").arg(candidates.size()));
        }

        return result;
    }
}

/**
 * @brief 执行单个候选方案的求解任务（在工作线程中执行）
 *
 * 此函数是 TaskCommand::work 的实际实现，运行在 DbWorkerThread 中。
 * 它负责：
 * 1. 检查取消状态（协作式取消）
 * 2. 创建独立的 MultiAgentSolver 实例
 * 3. 执行 MAPF 路径规划
 * 4. 捕获异常并记录日志
 *
 * @param task 求解任务数据（包含候选方案、图、超时等）
 * @return SolveResult 求解结果（成功/失败、路径、耗时等）
 */
ConcurrentCombinationSolver::SolveResult
ConcurrentCombinationSolver::executeSolveTask(const SolveTask& task)
{
    SolveResult result;
    result.candidateIndex = task.candidateIndex;
    result.solvedAgvs = task.candidate.includedAgvs;
    result.failedAgvs = task.candidate.excludedAgvs;
    result.waitingAgvOriginalGoals = task.candidate.waitingAgvOriginalGoals;  // 传递等待车信息

    // ========== 协作式取消检查 ==========
    // 早期退出：检查双重取消标志
    // 1. cancelFlag: 自定义标志（首个任务成功时设置）
    // 2. cancellationToken: TaskHandle 的取消令牌（TaskManager 取消时设置）
    if ((task.cancelFlag && task.cancelFlag->load()) ||
        (task.cancellationToken && task.cancellationToken->isCanceled())) {
        result.success = false;
        result.errorMessage = "被其他成功的求解取消";
        return result;
    }

    if (task.candidate.requests.empty()) {
        result.success = false;
        result.errorMessage = "候选组合为空";
        return result;
    }

    auto startTime = std::chrono::steady_clock::now();
    const bool hasDeadline = task.timeout > 0.0;
    const auto deadline = hasDeadline
        ? startTime + std::chrono::duration<double>(task.timeout)
        : std::chrono::steady_clock::time_point::max();

    auto shouldStop = [cancelFlag = task.cancelFlag,
                       token = task.cancellationToken,
                       deadline]() -> bool {
        if (cancelFlag && cancelFlag->load()) {
            return true;
        }
        if (token && token->isCanceled()) {
            return true;
        }
        if (deadline != std::chrono::steady_clock::time_point::max() &&
            std::chrono::steady_clock::now() > deadline) {
            return true;
        }
        return false;
    };

    if (shouldStop()) {
        result.success = false;
        result.errorMessage = "求解在开始前被取消/超时";
        return result;
    }

    try {
        // ========== 创建独立的求解器实例 ==========
        // 注意：每个线程必须创建独立的 MultiAgentSolver，避免线程安全问题
        pathfinding::MultiAgentSolver solver;
        solver.setLogger(task.logger);
        solver.setVerboseLogging(false);  // 并发时禁用详细日志（减少日志竞争）
        solver.setCancelCallback(shouldStop);
        solver.buildFromGraph(task.graph);

        // ========== 执行 MAPF 路径规划 ==========
        std::vector<pathfinding::AgentPlan> plans;
        bool success = solver.solve(task.candidate.requests, plans, task.suboptimality);

        auto endTime = std::chrono::steady_clock::now();
        result.solveTime = std::chrono::duration<double>(endTime - startTime).count();

        if (success) {
            result.success = true;
            result.plans = plans;
        } else {
            result.success = false;
            result.errorMessage = shouldStop()
                                      ? "MAPF求解被取消/超时"
                                      : "MAPF求解失败";
        }

    } catch (const std::exception& e) {
        // ========== 异常捕获 ==========
        // 确保单个任务失败不影响其他任务
        auto endTime = std::chrono::steady_clock::now();
        result.solveTime = std::chrono::duration<double>(endTime - startTime).count();

        result.success = false;
        result.errorMessage = QString("求解异常: %1").arg(e.what());

        if (task.logger) {
            task.logger->error(QString("并发求解任务#%1异常: %2")
                .arg(task.candidateIndex)
                .arg(e.what()));
        }
    }

    return result;
}

QHash<QString, std::vector<pathfinding::AgentRequest>>
ConcurrentCombinationSolver::groupByGoal(const std::vector<pathfinding::AgentRequest>& requests)
{
    QHash<QString, std::vector<pathfinding::AgentRequest>> groups;
    for (const auto& req : requests) {
        groups[req.goalId].push_back(req);
    }
    return groups;
}

std::pair<pathfinding::AgentRequest, std::vector<pathfinding::AgentRequest>>
ConcurrentCombinationSolver::pickWinnerAndWaiters(const std::vector<pathfinding::AgentRequest>& group)
{
    // 按请求时间优先：requestedAt 越小越早，若相等再按 agvNumber 升序
    auto sorted = group;
    std::sort(sorted.begin(), sorted.end(), [](const auto& a, const auto& b) {
        if (a.requestOrder != b.requestOrder) {
            return a.requestOrder < b.requestOrder;
        }
        return a.agvNumber < b.agvNumber;
    });
    pathfinding::AgentRequest winner = sorted.front();

    std::vector<pathfinding::AgentRequest> waiters;
    for (size_t i = 1; i < sorted.size(); ++i) {
        auto waiter = sorted[i];
        // 等待替身：start==goal
        waiter.startId = waiter.goalId;
        waiters.push_back(std::move(waiter));
    }
    return {winner, waiters};
}

int ConcurrentCombinationSolver::scoreCombo(const SolveCandidate& combo)
{
    // 粗评分：请求数量越少分数越小（优先），可替换为更复杂评分
    return static_cast<int>(combo.requests.size());
}

std::vector<ConcurrentCombinationSolver::SolveCandidate>
ConcurrentCombinationSolver::generateCandidates(
    const std::vector<pathfinding::AgentRequest>& requests,
    int maxCandidates)
{
    std::vector<SolveCandidate> candidates;
    if (requests.empty()) {
        return candidates;
    }

    // 1) 按 goal 分组
    auto groups = groupByGoal(requests);
    if (groups.empty()) {
        return candidates;
    }

    // 如果存在重复 goal，跳过组合展开，直接使用原始请求作为单一候选
    bool hasDuplicateGoal = false;
    for (auto it = groups.begin(); it != groups.end(); ++it) {
        if (it.value().size() > 1) {
            hasDuplicateGoal = true;
            break;
        }
    }
    if (!hasDuplicateGoal) {
        SolveCandidate direct;
        direct.requests = requests;
        for (const auto& r : requests) {
            direct.includedAgvs.insert(r.agvNumber);
        }
        direct.priority = 0;
        candidates.push_back(std::move(direct));
        return candidates;
    }

    // 2) 针对每个 goal 生成 winner 选择：若该 goal 有多个 AGV，则每个 AGV 都作为一次 winner，其余设为等待（start==goal）
    std::vector<std::vector<pathfinding::AgentRequest>> perGroupChoices;
    std::vector<QHash<int, QString>> perGroupWaitingMaps;  // 跟踪每个组合的等待车信息
    perGroupChoices.reserve(groups.size());
    for (auto it = groups.begin(); it != groups.end(); ++it) {
        const auto& group = it.value();
        if (group.empty()) {
            continue;
        }
        std::vector<pathfinding::AgentRequest> sorted = group;
        std::sort(sorted.begin(), sorted.end(), [](const auto& a, const auto& b) {
            if (a.requestOrder != b.requestOrder) {
                return a.requestOrder < b.requestOrder;
            }
            return a.agvNumber < b.agvNumber;
        });
        std::vector<pathfinding::AgentRequest> waitersTemplate;
        // 该 goal 的所有候选（每个元素代表一个 winner 方案）
        std::vector<std::vector<pathfinding::AgentRequest>> goalChoices;
        std::vector<QHash<int, QString>> goalWaitingMaps;  // 每个选择对应的等待车信息
        goalChoices.reserve(sorted.size());
        goalWaitingMaps.reserve(sorted.size());
        for (size_t i = 0; i < sorted.size(); ++i) {
            std::vector<pathfinding::AgentRequest> choice;
            QHash<int, QString> waitingMap;
            choice.reserve(sorted.size());
            for (size_t j = 0; j < sorted.size(); ++j) {
                auto req = sorted[j];
                if (j != i) {
                    // 记录等待车原始目标
                    waitingMap.insert(req.agvNumber, req.goalId);
                    req.goalId = req.startId;  // waiter：start==goal
                }
                choice.push_back(std::move(req));
            }
            goalChoices.push_back(std::move(choice));
            goalWaitingMaps.push_back(std::move(waitingMap));
        }
        if (goalChoices.empty()) {
            continue;
        }
        // 展开到全局 choices 列表（同时跟踪等待车信息）
        if (perGroupChoices.empty()) {
            perGroupChoices = goalChoices;
            // 初始化等待车信息列表
            for (const auto& wm : goalWaitingMaps) {
                perGroupWaitingMaps.push_back(wm);
            }
        } else {
            std::vector<std::vector<pathfinding::AgentRequest>> next;
            std::vector<QHash<int, QString>> nextWaitingMaps;
            for (size_t baseIdx = 0; baseIdx < perGroupChoices.size(); ++baseIdx) {
                const auto& base = perGroupChoices[baseIdx];
                const auto& baseWaiting = perGroupWaitingMaps[baseIdx];
                for (size_t gcIdx = 0; gcIdx < goalChoices.size(); ++gcIdx) {
                    const auto& gchoice = goalChoices[gcIdx];
                    const auto& gcWaiting = goalWaitingMaps[gcIdx];
                    auto combined = base;
                    combined.insert(combined.end(), gchoice.begin(), gchoice.end());
                    // 合并等待车信息
                    auto combinedWaiting = baseWaiting;
                    for (auto wit = gcWaiting.begin(); wit != gcWaiting.end(); ++wit) {
                        combinedWaiting.insert(wit.key(), wit.value());
                    }
                    next.push_back(std::move(combined));
                    nextWaitingMaps.push_back(std::move(combinedWaiting));
                    if (maxCandidates > 0 &&
                        static_cast<int>(next.size()) >= maxCandidates) {
                        break;
                    }
                }
                if (maxCandidates > 0 &&
                    static_cast<int>(next.size()) >= maxCandidates) {
                    break;
                }
            }
            if (!next.empty()) {
                perGroupChoices.swap(next);
                perGroupWaitingMaps.swap(nextWaitingMaps);
            }
        }
        if (maxCandidates > 0 &&
            static_cast<int>(perGroupChoices.size()) >= maxCandidates) {
            break;
        }
    }

    // 3) 生成 SolveCandidate
    if (perGroupChoices.empty()) {
        SolveCandidate c;
        c.requests = requests;
        for (const auto& r : requests) {
            c.includedAgvs.insert(r.agvNumber);
        }
        c.priority = scoreCombo(c);
        candidates.push_back(std::move(c));
        return candidates;
    }

    for (size_t idx = 0; idx < perGroupChoices.size(); ++idx) {
        const auto& choice = perGroupChoices[idx];
        SolveCandidate c;
        c.requests = choice;
        for (const auto& r : choice) {
            c.includedAgvs.insert(r.agvNumber);
        }
        // 填充等待车原始目标信息
        if (idx < perGroupWaitingMaps.size()) {
            c.waitingAgvOriginalGoals = perGroupWaitingMaps[idx];
        }
        c.priority = scoreCombo(c);
        candidates.push_back(std::move(c));
        if (maxCandidates > 0 && static_cast<int>(candidates.size()) >= maxCandidates) {
            break;
        }
    }

    return candidates;
}

} // namespace dispatcher
} // namespace application
